import { PropertyGrid, PropertyGroup, TextProperty, DisplayProperty, CheckBoxProperty, ButtonProperty, SelectProperty, ButtonsProperty, Button, ColorProperty, NumberProperty, TextureProperty } from '../../third_party';
import SetValueCommand from '../../command/SetValueCommand';
import SetMaterialCommand from '../../command/SetMaterialCommand';
import SetMaterialColorCommand from '../../command/SetMaterialColorCommand';
import SetMaterialValueCommand from '../../command/SetMaterialValueCommand';
import SetMaterialMapCommand from '../../command/SetMaterialMapCommand';
import ShaderMaterialVertex from './shader/shader_material_vertex.glsl';
import ShaderMaterialFragment from './shader/shader_material_fragment.glsl';
import RawShaderMaterialVertex from './shader/raw_shader_material_vertex.glsl';
import RawShaderMaterialFragment from './shader/raw_shader_material_fragment.glsl';

import TextureSettingWindow from '../window/TextureSettingWindow.jsx';

import MaterialsSerializer from '../../serialization/material/MaterialsSerializer';
import MaterialUtils from '../../utils/MaterialUtils';

import Ajax from '../../utils/Ajax';
import Converter from '../../utils/Converter';

/**
 * 材质组件
 * @author tengge / https://github.com/tengge1
 */
class MaterialComponent extends React.Component {
    constructor(props) {
        super(props);

        this.selected = null;

        this.materials = {
            'LineBasicMaterial': _t('LineBasicMaterial'),
            'LineDashedMaterial': _t('LineDashedMaterial'),
            'MeshBasicMaterial': _t('MeshBasicMaterial'),
            'MeshDepthMaterial': _t('MeshDepthMaterial'),
            'MeshNormalMaterial': _t('MeshNormalMaterial'),
            'MeshLambertMaterial': _t('MeshLambertMaterial'),
            'MeshPhongMaterial': _t('MeshPhongMaterial'),
            'PointsMaterial': _t('PointCloudMaterial'),
            'MeshStandardMaterial': _t('MeshStandardMaterial'),
            'MeshPhysicalMaterial': _t('MeshPhysicalMaterial'),
            'SpriteMaterial': _t('SpriteMaterial'),
            'ShaderMaterial': _t('ShaderMaterial'),
            'RawShaderMaterial': _t('RawShaderMaterial')
        };

        this.vertexColors = {
            0: _t('No Colors'),
            1: _t('Face Colors'),
            2: _t('Vertex Colors'),
        };

        this.side = {
            0: _t('Front Side'),
            1: _t('Back Side'),
            2: _t('Double Side'),
        };

        this.blending = {
            0: _t('No Blending'),
            1: _t('Normal Blending'),
            2: _t('Additive Blending'),
            3: _t('Substractive Blending'),
            4: _t('Multiply Blending'),
            5: _t('Custom Blending'),
        };

        this.mapNames = [ // 用于判断属性是否是纹理
            'map',
            'alphaMap',
            'bumpMap',
            'normalMap',
            'displacementMap',
            'roughnessMap',
            'metalnessMap',
            'specularMap',
            'envMap',
            'lightMap',
            'aoMap',
            'emissiveMap',
        ];

        this.state = {
            show: false,
            expanded: false,

            type: null,

            showProgram: false,

            showColor: false,
            color: null,

            showRoughness: false,
            roughness: null,

            showMetalness: false,
            metalness: null,

            showEmissive: false,
            emissive: null,

            showSpecular: false,
            specular: null,

            showShininess: false,
            shininess: null,

            showClearCoat: false,
            clearCoat: null,

            showClearCoatRoughness: false,
            clearCoatRoughness: null,

            showVertexColors: false,
            vertexColors: null,

            showSkinning: false,
            skinning: null,

            showMap: false,
            map: null,

            showAlphaMap: false,
            alphaMap: null,

            showBumpMap: false,
            bumpMap: null,
            bumpScale: null,

            showNormalMap: false,
            normalMap: null,

            showDisplacementMap: false,
            displacementMap: null,
            displacementScale: null,

            showRoughnessMap: false,
            roughnessMap: null,

            showMetalnessMap: false,
            metalnessMap: null,

            showSpecularMap: false,
            specularMap: null,

            showEnvMap: false,
            envMap: null,

            reflectivity: null,

            showLightMap: false,
            lightMap: null,

            showAoMap: false,
            aoMap: null,
            aoScale: null,

            showEmissiveMap: false,
            emissiveMap: null,

            showSide: false,
            side: null,

            showFlatShading: false,
            flatShading: null,

            showBlending: false,
            blending: null,

            showOpacity: false,
            opacity: 1,

            showTransparent: false,
            transparent: false,

            showAlphaTest: false,
            alphaTest: 1,

            showWireframe: false,
            wireframe: false,
            wireframeLinewidth: 1,
        };

        this.handleExpand = this.handleExpand.bind(this);
        this.handleUpdate = this.handleUpdate.bind(this);

        this.handleChange = this.handleChange.bind(this);

        this.handleTextureSetting = this.handleTextureSetting.bind(this);

        this.editProgramInfo = this.editProgramInfo.bind(this);
        this.saveProgramInfo = this.saveProgramInfo.bind(this);

        this.editVertexShader = this.editVertexShader.bind(this);
        this.saveVertexShader = this.saveVertexShader.bind(this);

        this.editFragmentShader = this.editFragmentShader.bind(this);
        this.saveFragmentShader = this.saveFragmentShader.bind(this);

        this.onSave = this.onSave.bind(this);
        this.onLoad = this.onLoad.bind(this);
    }

    render() {
        const { show, expanded, type, showProgram, showColor, color, showRoughness, roughness, showMetalness, metalness, showEmissive, emissive, showSpecular, specular, showShininess, shininess, showClearCoat, clearCoat, showClearCoatRoughness, clearCoatRoughness, showVertexColors, vertexColors, showSkinning, skinning,
            showMap, map, showAlphaMap, alphaMap, showBumpMap, bumpMap, bumpScale, showNormalMap, normalMap, showDisplacementMap, displacementMap,
            displacementScale, showRoughnessMap, roughnessMap, showMetalnessMap, metalnessMap, showSpecularMap, specularMap, showEnvMap, envMap,
            reflectivity, showLightMap, lightMap, showAoMap, aoMap, aoScale, showEmissiveMap, emissiveMap, showSide, side, showFlatShading, flatShading, showBlending, blending, showOpacity, opacity, showTransparent, transparent, showAlphaTest, alphaTest, showWireframe, wireframe, wireframeLinewidth } = this.state;

        if (!show) {
            return null;
        }

        return <PropertyGroup title={_t('Material Component')} show={show} expanded={expanded} onExpand={this.handleExpand}>
            <ButtonsProperty label={''}>
                <Button onClick={this.onSave}>{_t('Save')}</Button>
                <Button onClick={this.onLoad}>{_t('Select')}</Button>
            </ButtonsProperty>
            <SelectProperty label={_t('Type')} options={this.materials} name={'type'} value={type} onChange={this.handleChange}></SelectProperty>
            <ButtonProperty label={_t('ShaderInfo')} text={_t('Edit')} show={showProgram} onChange={this.editProgramInfo}></ButtonProperty>
            <ButtonProperty label={_t('Vertex Shader')} text={_t('Edit')} show={showProgram} onChange={this.editVertexShader}></ButtonProperty>
            <ButtonProperty label={_t('Frag Shader')} text={_t('Edit')} show={showProgram} onChange={this.editFragmentShader}></ButtonProperty>
            <ColorProperty label={_t('Color')} name={'color'} value={color} show={showColor} onChange={this.handleChange}></ColorProperty>
            <NumberProperty label={_t('Roughness')} name={'roughness'} value={roughness} show={showRoughness} onChange={this.handleChange}></NumberProperty>
            <NumberProperty label={_t('MetalNess')} name={'metalness'} value={metalness} show={showMetalness} onChange={this.handleChange}></NumberProperty>
            <ColorProperty label={_t('Emissive')} name={'emissive'} value={emissive} show={showEmissive} onChange={this.handleChange}></ColorProperty>
            <ColorProperty label={_t('Specular')} name={'specular'} value={specular} show={showSpecular} onChange={this.handleChange}></ColorProperty>
            <NumberProperty label={_t('Shininess')} name={'shininess'} value={shininess} show={showShininess} onChange={this.handleChange}></NumberProperty>
            <NumberProperty label={_t('ClearCoat')} name={'clearCoat'} value={clearCoat} show={showClearCoat} onChange={this.handleChange}></NumberProperty>
            <NumberProperty label={_t('ClearCoatRoughness')} name={'clearCoatRoughness'} value={clearCoatRoughness} show={showClearCoatRoughness} onChange={this.handleChange}></NumberProperty>
            <SelectProperty label={_t('Vertex Color')} options={this.vertexColors} name={'vertexColors'} value={vertexColors} show={showVertexColors} onChange={this.handleChange}></SelectProperty>
            <CheckBoxProperty label={_t('Skin')} name={'skinning'} value={skinning} show={showSkinning} onChange={this.handleChange}></CheckBoxProperty>
            <TextureProperty label={_t('Map')} name={'map'} value={map} show={showMap} onChange={this.handleChange}></TextureProperty>
            <ButtonProperty text={_t('Texture Settings')} onChange={this.handleTextureSetting}></ButtonProperty>
            <TextureProperty label={_t('AlphaMap')} name={'alphaMap'} value={alphaMap} show={showAlphaMap} onChange={this.handleChange}></TextureProperty>
            <TextureProperty label={_t('BumpMap')} name={'bumpMap'} value={bumpMap} show={showBumpMap} onChange={this.handleChange}></TextureProperty>
            <NumberProperty label={_t('Bump Scale')} name={'bumpScale'} value={bumpScale} show={showBumpMap} onChange={this.handleChange}></NumberProperty>
            <TextureProperty label={_t('NormalMap')} name={'normalMap'} value={normalMap} show={showNormalMap} onChange={this.handleChange}></TextureProperty>
            <TextureProperty label={_t('DisplacementMap')} name={'displacementMap'} value={displacementMap} show={showDisplacementMap} onChange={this.handleChange}></TextureProperty>
            <NumberProperty label={_t('Displace Scale')} name={'displacementScale'} value={displacementScale} show={showDisplacementMap} onChange={this.handleChange}></NumberProperty>
            <TextureProperty label={_t('RoughnessMap')} name={'roughnessMap'} value={roughnessMap} show={showRoughnessMap} onChange={this.handleChange}></TextureProperty>
            <TextureProperty label={_t('MetalnessMap')} name={'metalnessMap'} value={metalnessMap} show={showMetalnessMap} onChange={this.handleChange}></TextureProperty>
            <TextureProperty label={_t('SpecularMap')} name={'specularMap'} value={specularMap} show={showSpecularMap} onChange={this.handleChange}></TextureProperty>
            <TextureProperty label={_t('EnvMap')} name={'envMap'} value={envMap} show={showEnvMap} onChange={this.handleChange}></TextureProperty>
            <NumberProperty label={_t('Reflectivity')} name={'reflectivity'} value={reflectivity} show={showEnvMap} onChange={this.handleChange}></NumberProperty>
            <TextureProperty label={_t('LightMap')} name={'lightMap'} value={lightMap} show={showLightMap} onChange={this.handleChange}></TextureProperty>
            <TextureProperty label={_t('AoMap')} name={'aoMap'} value={aoMap} show={showAoMap} onChange={this.handleChange}></TextureProperty>
            <NumberProperty label={_t('Ao Scale')} name={'aoScale'} value={aoScale} show={showAoMap} onChange={this.handleChange}></NumberProperty>
            <TextureProperty label={_t('EmissiveMap')} name={'emissiveMap'} value={emissiveMap} show={showEmissiveMap} onChange={this.handleChange}></TextureProperty>
            <SelectProperty label={_t('Side')} options={this.side} name={'side'} value={side} onChange={this.handleChange}></SelectProperty>
            <CheckBoxProperty label={_t('Flat Shading')} name={'flatShading'} value={flatShading} onChange={this.handleChange}></CheckBoxProperty>
            <SelectProperty label={_t('Blending')} options={this.blending} name={'blending'} value={blending} onChange={this.handleChange}></SelectProperty>
            <NumberProperty label={_t('Opacity')} name={'opacity'} value={opacity} onChange={this.handleChange}></NumberProperty>
            <CheckBoxProperty label={_t('Transparent')} name={'transparent'} value={transparent} onChange={this.handleChange}></CheckBoxProperty>
            <NumberProperty label={_t('AlphaTest')} name={'alphaTest'} value={alphaTest} onChange={this.handleChange}></NumberProperty>
            <CheckBoxProperty label={_t('Wireframe')} name={'wireframe'} value={wireframe} onChange={this.handleChange}></CheckBoxProperty>
            <NumberProperty label={_t('WireWidth')} name={'wireframeLinewidth'} value={wireframeLinewidth} onChange={this.handleChange}></NumberProperty>
        </PropertyGroup>;
    }

    componentDidMount() {
        app.on(`objectSelected.MaterialComponent`, this.handleUpdate);
        app.on(`objectChanged.MaterialComponent`, this.handleUpdate);
    }

    handleExpand(expanded) {
        this.setState({
            expanded,
        });
    }

    handleUpdate() {
        const editor = app.editor;

        if (!editor.selected || !(editor.selected.material instanceof THREE.Material)) {
            this.setState({
                show: false,
            });
            return;
        }

        this.selected = editor.selected;

        let material = this.selected.material;

        let state = {
            show: true,
            type: material.type,
            showProgram: material instanceof THREE.ShaderMaterial || material instanceof THREE.RawShaderMaterial,
        };

        if (material.color) {
            state.showColor = true;
            state.color = `#${material.color.getHexString()}`;
        } else {
            state.showColor = false;
        }

        if (material.roughness !== undefined) {
            state.showRoughness = true;
            state.roughness = material.roughness;
        } else {
            state.showRoughness = false;
        }

        if (material.metalness !== undefined) {
            state.showMetalness = true;
            state.metalness = material.metalness;
        } else {
            state.showMetalness = false;
        }

        if (material.emissive !== undefined) {
            state.showEmissive = true;
            state.emissive = `#${material.emissive.getHexString()}`;
        } else {
            state.showEmissive = false;
        }

        if (material.specular !== undefined) {
            state.showSpecular = true;
            state.specular = `#${material.specular.getHexString()}`;
        } else {
            state.showSpecular = false;
        }

        if (material.shininess !== undefined) {
            state.showShininess = true;
            state.shininess = material.shininess;
        } else {
            state.showShininess = false;
        }

        if (material.clearCoat !== undefined) {
            state.showClearCoat = true;
            state.clearCoat = material.clearCoat;
        } else {
            state.showClearCoat = false;
        }

        if (material.clearCoatRoughness !== undefined) {
            state.showClearCoatRoughness = true;
            state.clearCoatRoughness = material.clearCoatRoughness;
        } else {
            state.showClearCoatRoughness = false;
        }

        if (material.vertexColors !== undefined) {
            state.showVertexColors = true;
            state.vertexColors = material.vertexColors;
        } else {
            state.showVertexColors = false;
        }

        if (material.skinning !== undefined) {
            state.showSkinning = true;
            state.skinning = material.skinning;
        } else {
            state.showSkinning = false;
        }

        if (material.map !== undefined) {
            state.showMap = true;
            state.map = material.map;
        } else {
            state.showMap = false;
        }

        if (material.alphaMap !== undefined) {
            state.showAlphaMap = true;
            state.alphaMap = material.alphaMap;
        } else {
            state.showAlphaMap = false;
        }

        if (material.bumpMap !== undefined) {
            state.showBumpMap = true;
            state.bumpMap = material.bumpMap;
            state.bumpScale = material.bumpScale;
        } else {
            state.showBumpMap = false;
        }

        if (material.normalMap !== undefined) {
            state.showNormalMap = true;
            state.normalMap = material.normalMap;
        } else {
            state.showNormalMap = false;
        }

        if (material.displacementMap !== undefined) {
            state.showDisplacementMap = true;
            state.displacementMap = material.displacementMap;
            state.displacementScale = material.displacementScale;
        } else {
            state.showDisplacementMap = false;
        }

        if (material.roughnessMap !== undefined) {
            state.showRoughnessMap = true;
            state.roughnessMap = material.roughnessMap;
        } else {
            state.showRoughnessMap = false;
        }

        if (material.metalnessMap !== undefined) {
            state.showMetalnessMap = true;
            state.metalnessMap = material.metalnessMap;
        } else {
            state.showMetalnessMap = false;
        }

        if (material.specularMap !== undefined) {
            state.showSpecularMap = true;
            state.specularMap = material.specularMap;
        } else {
            state.showSpecularMap = false;
        }

        if (material.envMap !== undefined) {
            state.showEnvMap = true;
            state.envMap = material.envMap;

            if (material.reflectivity !== undefined) {
                state.reflectivity = material.reflectivity;
            }
        } else {
            state.showEnvMap = false;
        }

        if (material.lightMap !== undefined) {
            state.showLightMap = true;
            state.lightMap = material.lightMap;
        } else {
            state.showLightMap = false;
        }

        if (material.aoMap !== undefined) {
            state.showAoMap = true;
            state.aoMap = material.aoMap;
            state.aoScale = material.aoMapIntensity;
        } else {
            state.showAoMap = false;
        }

        if (material.emissiveMap !== undefined) {
            state.showEmissiveMap = true;
            state.emissiveMap = material.emissiveMap;
        } else {
            state.showEmissiveMap = false;
        }

        if (material.side !== undefined) {
            state.side = material.side;
        }

        if (material.flatShading !== undefined) {
            state.flatShading = material.flatShading;
        }

        if (material.blending !== undefined) {
            state.blending = material.blending;
        }

        if (material.opacity !== undefined) {
            state.opacity = material.opacity;
        }

        if (material.transparent !== undefined) {
            state.transparent = material.transparent;
        }

        if (material.alphaTest !== undefined) {
            state.alphaTest = material.alphaTest;
        }

        if (material.wireframe !== undefined) {
            state.wireframe = material.wireframe;
        }

        if (material.wireframeLinewidth !== undefined) {
            state.wireframeLinewidth = material.wireframeLinewidth;
        }

        this.setState(state);
    }

    handleChange(value, name) {
        // 当name是纹理时，value为null表示不显示纹理，不应该跳过。
        if (value === null && this.mapNames.indexOf(name) === -1) {
            this.setState({
                [name]: value,
            });
            return;
        }

        const editor = app.editor;
        const object = this.selected;
        let material = object.material;

        const { type, showProgram, showColor, color, showRoughness, roughness, showMetalness, metalness, showEmissive, emissive, showSpecular, specular, showShininess, shininess, showClearCoat, clearCoat, showClearCoatRoughness, clearCoatRoughness, showVertexColors, vertexColors, showSkinning, skinning,
            showMap, map, showAlphaMap, alphaMap, showBumpMap, bumpMap, bumpScale, showNormalMap, normalMap, showDisplacementMap, displacementMap,
            displacementScale, showRoughnessMap, roughnessMap, showMetalnessMap, metalnessMap, showSpecularMap, specularMap, showEnvMap, envMap,
            reflectivity, showLightMap, lightMap, showAoMap, aoMap, aoScale, showEmissiveMap, emissiveMap, showSide, side, showFlatShading, flatShading, showBlending, blending, showOpacity, opacity, showTransparent, transparent, showAlphaTest, alphaTest, showWireframe, wireframe, wireframeLinewidth } = Object.assign({}, this.state, {
                [name]: value,
            });

        if (material instanceof THREE[type] === false) {
            material = new THREE[type]();

            if (material instanceof THREE.ShaderMaterial) {
                material.uniforms = {
                    time: {
                        value: 1.0
                    }
                };
                material.vertexShader = ShaderMaterialVertex;
                material.fragmentShader = ShaderMaterialFragment;
            }

            if (material instanceof THREE.RawShaderMaterial) {
                material.uniforms = {
                    time: {
                        value: 1.0
                    }
                };
                material.vertexShader = RawShaderMaterialVertex;
                material.fragmentShader = RawShaderMaterialFragment;
            }

            editor.execute(new SetMaterialCommand(object, material), _t('New Material') + ':' + type);
        }

        if (material.color !== undefined && `#${material.color.getHexString()}` !== color) {
            editor.execute(new SetMaterialColorCommand(object, 'color', color));
        }

        if (material.roughness !== undefined && Math.abs(material.roughness - roughness) >= 0.01) {
            editor.execute(new SetMaterialValueCommand(object, 'roughness', roughness));
        }

        if (material.metalness !== undefined && Math.abs(material.metalness - metalness) >= 0.01) {
            editor.execute(new SetMaterialValueCommand(object, 'metalness', metalness));
        }

        if (material.emissive !== undefined && `#${material.emissive.getHexString()}` !== emissive) {
            editor.execute(new SetMaterialColorCommand(object, 'emissive', emissive));
        }

        if (material.specular !== undefined && `#${material.specular.getHexString()}` !== specular) {
            editor.execute(new SetMaterialColorCommand(object, 'specular', specular));
        }

        if (material.shininess !== undefined && Math.abs(material.shininess - shininess) >= 0.01) {
            editor.execute(new SetMaterialValueCommand(object, 'shininess', shininess));
        }

        if (material.clearCoat !== undefined && Math.abs(material.clearCoat - clearCoat) >= 0.01) {
            editor.execute(new SetMaterialValueCommand(object, 'clearCoat', clearCoat));
        }

        if (material.clearCoatRoughness !== undefined && Math.abs(material.clearCoatRoughness - clearCoatRoughness) >= 0.01) {
            editor.execute(new SetMaterialValueCommand(object, 'clearCoatRoughness', clearCoatRoughness));
        }

        if (material.vertexColors !== undefined && material.vertexColors !== vertexColors) {
            editor.execute(new SetMaterialValueCommand(object, 'vertexColors', vertexColors));
        }

        if (material.skinning !== undefined && material.skinning !== skinning) {
            editor.execute(new SetMaterialValueCommand(object, 'skinning', skinning));
        }

        if (name === 'map' && material.map !== undefined) {
            if (material.map !== map) {
                editor.execute(new SetMaterialMapCommand(object, 'map', map));
            } else {

            }
        }

        if (name === 'alphaMap' && material.alphaMap !== undefined) {
            if (material.alphaMap !== alphaMap) {
                editor.execute(new SetMaterialMapCommand(object, 'alphaMap', alphaMap));
            }
        }

        if (name === 'bumpMap' && material.bumpMap !== undefined) {
            if (material.bumpMap !== bumpMap) {
                editor.execute(new SetMaterialMapCommand(object, 'bumpMap', bumpMap));
            }
        }

        if (name === 'bumpScale' && material.bumpScale !== undefined) {
            editor.execute(new SetMaterialValueCommand(object, 'bumpScale', bumpScale));
        }

        if (name === 'normalMap' && material.normalMap !== undefined) {
            if (material.normalMap !== normalMap) {
                editor.execute(new SetMaterialMapCommand(object, 'normalMap', normalMap));
            }
        }

        if (name === 'displacementMap' && material.displacementMap !== undefined) {
            if (material.displacementMap !== displacementMap) {
                editor.execute(new SetMaterialMapCommand(object, 'displacementMap', displacementMap));
            }
        }

        if (name === 'displacementScale' && material.displacementScale !== undefined) {
            editor.execute(new SetMaterialValueCommand(object, 'displacementScale', displacementScale));
        }

        if (name === 'roughnessMap' && material.roughnessMap !== undefined) {
            if (material.roughnessMap !== roughnessMap) {
                editor.execute(new SetMaterialMapCommand(object, 'roughnessMap', roughnessMap));
            }
        }

        if (name === 'metalnessMap' && material.metalnessMap !== undefined) {
            if (material.metalnessMap !== metalnessMap) {
                editor.execute(new SetMaterialMapCommand(object, 'metalnessMap', metalnessMap));
            }
        }

        if (name === 'specularMap' && material.specularMap !== undefined) {
            if (material.specularMap !== specularMap) {
                editor.execute(new SetMaterialMapCommand(object, 'specularMap', specularMap));
            }
        }

        if (name === 'envMap' && material.envMap !== undefined) {
            if (material.envMap !== envMap) {
                editor.execute(new SetMaterialMapCommand(object, 'envMap', envMap));
            }
        }

        if (name === 'reflectivity' && material.reflectivity !== undefined) {
            editor.execute(new SetMaterialValueCommand(object, 'reflectivity', reflectivity));
        }

        if (name === 'lightMap' && material.lightMap !== undefined) {
            if (material.lightMap !== lightMap) {
                editor.execute(new SetMaterialMapCommand(object, 'lightMap', lightMap));
            }
        }

        if (name === 'aoMap' && material.aoMap !== undefined) {
            if (material.aoMap !== aoMap) {
                editor.execute(new SetMaterialMapCommand(object, 'aoMap', aoMap));
            }
        }

        if (name === 'aoScale' && material.aoMapIntensity !== undefined) {
            editor.execute(new SetMaterialValueCommand(object, 'aoMapIntensity', aoScale));
        }

        if (name === 'emissiveMap' && material.emissiveMap !== undefined) {
            if (material.emissiveMap !== emissiveMap) {
                editor.execute(new SetMaterialMapCommand(object, 'emissiveMap', emissiveMap));
            }
        }

        if (material.side !== undefined && material.side !== side) {
            editor.execute(new SetMaterialValueCommand(object, 'side', side));
        }

        if (material.flatShading !== undefined && material.flatShading != flatShading) {
            editor.execute(new SetMaterialValueCommand(object, 'flatShading', flatShading));
        }

        if (material.blending !== undefined && material.blending !== blending) {
            editor.execute(new SetMaterialValueCommand(object, 'blending', blending));
        }

        if (material.opacity !== undefined && Math.abs(material.opacity - opacity) >= 0.01) {
            editor.execute(new SetMaterialValueCommand(object, 'opacity', opacity));
        }

        if (material.transparent !== undefined && material.transparent !== transparent) {
            editor.execute(new SetMaterialValueCommand(object, 'transparent', transparent));
        }

        if (material.alphaTest !== undefined && Math.abs(material.alphaTest - alphaTest) >= 0.01) {
            editor.execute(new SetMaterialValueCommand(object, 'alphaTest', alphaTest));
        }

        if (material.wireframe !== undefined && material.wireframe !== wireframe) {
            editor.execute(new SetMaterialValueCommand(object, 'wireframe', wireframe));
        }

        if (material.wireframeLinewidth !== undefined && Math.abs(material.wireframeLinewidth - wireframeLinewidth) >= 0.01) {
            editor.execute(new SetMaterialValueCommand(object, 'wireframeLinewidth', wireframeLinewidth));
        }

        app.call(`objectChanged`, this, this.selected);
    }

    handleTextureSetting() {
        if (!this.selected.material.map) {
            app.toast(_t('Please select texture first.'));
            return;
        }

        let win = app.createElement(TextureSettingWindow, {
            map: this.selected.material.map,
        });

        app.addElement(win);
    }

    editProgramInfo() {
        let material = this.selected.material;

        let obj = {
            defines: material.defines,
            uniforms: material.uniforms,
            attributes: material.attributes
        };

        app.call(`editScript`, this, material.uuid, this.selected.name + '-ProgramInfo', 'json', JSON.stringify(obj), this.saveProgramInfo);
    }

    saveProgramInfo(uuid, name, type, source) {
        let material = this.selected.material;

        try {
            let obj = JSON.parse(source);
            material.defines = obj.defines;
            material.uniforms = obj.uniforms;
            material.attributes = obj.attributes;
            material.needsUpdate = true;
        } catch (e) {
            app.error(this.selected.name + `-${_t('Shader cannot be parsed.')}`);
        }
    }

    editVertexShader() {
        let material = this.selected.material;

        app.call(`editScript`, this, material.uuid, this.selected.name + '-VertexShader', 'vertexShader', material.vertexShader, this.saveVertexShader);
    }

    saveVertexShader(uuid, name, type, source) {
        let material = this.selected.material;
        material.vertexShader = source;
        material.needsUpdate = true;
    }

    editFragmentShader() {
        let material = this.selected.material;

        app.call(`editScript`, this, material.uuid, this.selected.name + '-FragmentShader', 'fragmentShader', material.fragmentShader, this.saveFragmentShader);
    }

    saveFragmentShader(uuid, name, type, source) {
        let material = this.selected.material;
        material.fragmentShader = source;
        material.needsUpdate = true;
    }

    // --------------------------------------- 材质保存载入 --------------------------------------------------

    onSave() {
        app.prompt({
            title: _t('Please enter material name'),
            content: _t('Name'),
            value: _t('New Material'),
            onOK: value => {
                this.commitSave(value);
            }
        });
    }

    commitSave(name) {
        const material = this.selected.material;
        const data = (new MaterialsSerializer()).toJSON(material);

        // 材质球图片
        const dataURL = MaterialUtils.createMaterialImage(material).toDataURL('image/png');

        const file = Converter.dataURLtoFile(dataURL, name);

        // 上传图片
        Ajax.post(`${app.options.server}/api/Upload/Upload`, {
            file: file
        }, result => {
            let obj = JSON.parse(result);

            if (obj.Code === 300) {
                app.toast(_t(obj.Msg));
                return;
            }

            Ajax.post(`${app.options.server}/api/Material/Save`, {
                Name: name,
                Data: JSON.stringify(data),
                Thumbnail: obj.Data.url
            }, result => {
                obj = JSON.parse(result);
                if (obj.Code === 200) {
                    app.call(`showBottomPanel`, this, 'material');
                }
                app.toast(_t(obj.Msg));
            });
        });
    }

    onLoad() {
        app.call(`selectBottomPanel`, this, 'material');
        app.toast(_t('Please click material on material panel.'));
        app.on(`selectMaterial.MaterialComponent`, this.onWaitingForMaterial.bind(this));
    }

    onWaitingForMaterial(material) {
        app.on(`selectMaterial.MaterialComponent`, null);

        if (this.selected.material) {
            this.selected.material.dispose();
        }

        this.selected.material = material;

        app.call('objectChanged', this, this.selected);
    }
}

export default MaterialComponent;